package com.kgc.est.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kgc.est.constants.Constants;
import com.kgc.est.constants.MaintainStatusEnum;
import com.kgc.est.constants.ResultEnum;
import com.kgc.est.mapper.AppointmentMapper;
import com.kgc.est.mapper.EvaluateMapper;
import com.kgc.est.mapper.MaintainOrderFlowMapper;
import com.kgc.est.mapper.MaintainOrderMapper;
import com.kgc.est.pojo.*;
import com.kgc.est.request.AppointmentReq;
import com.kgc.est.utils.DateUtils;
import com.kgc.est.utils.Result;
import com.kgc.est.utils.ResultUtils;
import com.kgc.est.utils.redis.RedisKeyUtils;
import com.kgc.est.utils.redis.RedisUtils;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.print.attribute.standard.OrientationRequested;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Transactional
@RestController
@RequestMapping("/maintain")
public class MaintainOrderServiceImpl {

    Logger log = LoggerFactory.getLogger(MaintainOrderServiceImpl.class);

    @Autowired(required = false)
    private RedisUtils redisUtils;

    @Autowired(required = false)
    private MaintainOrderMapper maintainOrderMapper;

    @Autowired(required = false)
    private AppointmentMapper appointmentMapper;

    @Autowired(required = false)
    private EvaluateMapper evaluateMapper;

    @Autowired(required = false)
    private MaintainOrderFlowMapper maintainOrderFlowMapper;

    /**
     * 根据入参信息
     *      生成订单编号
     *      生成预约信息
     *      生成订单信息
     *      生成订单流水
     * @param appointmentReq
     * @return
     */
    @PostMapping("/submit")
    public Result submit(@RequestBody AppointmentReq appointmentReq) throws ParseException {

        log.info("appointmentReq:{}",appointmentReq);
        String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.PREFIX_TOKEN, appointmentReq.getToken());

        String value = redisUtils.getValue(key);

        Users users = JSON.parseObject(value, Users.class);

        //验证入参
        //验证手机号
        if (!checkPhone(appointmentReq.getPhone())){
            return ResultUtils.returnFail("手机号不正确", ResultEnum.FAIL.getCode());
        }

        //验证地址
        if (!checkAddress(appointmentReq.getAdress())){
            return ResultUtils.returnFail("地址不能为空", ResultEnum.FAIL.getCode());
        }

        //验证时间
        if (!checkDate(appointmentReq.getAppintDate())){
            return ResultUtils.returnFail("时间错误", ResultEnum.FAIL.getCode());
        }

        //验证时间区间
        if (!checkTemporalInterval(appointmentReq.getTemporalInterval())){
            return ResultUtils.returnFail("时间区间错误", ResultEnum.FAIL.getCode());
        }

        //验证验证码是否正确
        if (checkSmsCode(appointmentReq.getPhone(),appointmentReq.getSms())){
            return ResultUtils.returnFail("验证码错误", ResultEnum.FAIL.getCode());

        }

        String orderNo = createOrderNo();

        //生成预约对象
        Appointment appointment = new Appointment();
        appointment.setUserId(users.getId());
        appointment.setPhone(appointmentReq.getPhone());
        appointment.setAdress(appointmentReq.getAdress());
        appointment.setAppintDate(appointmentReq.getAppintDate());
        appointment.setTemporalInterval(appointmentReq.getTemporalInterval());
        appointment.setStatus(Constants.Order.AppointStatus.APPOINT);

        //查询评估表
        Evaluate evaluate = evaluateMapper.selectById(appointmentReq.getEvaluateId());

        //保存预约信息
        appointmentMapper.insert(appointment);
        //保存订单信息
        MaintainOrder maintainOrder = new MaintainOrder();
        maintainOrder.setEvaluateId(appointmentReq.getEvaluateId());
        maintainOrder.setModelId(evaluate.getModelId());
        maintainOrder.setCreatedUserId(users.getId());
        maintainOrder.setUserId(users.getId());
        maintainOrder.setSubscription(evaluate.getSubscription());
        maintainOrder.setOrderNo(orderNo);
        maintainOrder.setStatus(Constants.Order.MaintainStatus.APPOINT);
        maintainOrderMapper.insert(maintainOrder);

        //保存订单流水
        MaintainOrderFlow maintainOrderFlow= new MaintainOrderFlow();
        maintainOrderFlow.setOrderNo(orderNo);
        maintainOrderFlow.setOrderStatus(Constants.Order.MaintainStatus.APPOINT);
        maintainOrderFlow.setCreatedUserId(users.getId());
        maintainOrderFlow.setOperationUId(users.getId());
        maintainOrderFlow.setOperationName(users.getUserName());
        maintainOrderFlow.setOrderStatusDesc(MaintainStatusEnum.APPOINT.getMsg());
        maintainOrderFlowMapper.insert(maintainOrderFlow);

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("orderNo",orderNo);
        //返回订单编号
        return ResultUtils.returnDataSuccess(map);
    }


    /**
     * 生成订单编号
     * @return
     * @throws ParseException
     */
    private String createOrderNo()throws ParseException {
        //订单编号：不同企业不一样，但有一点是一样的，不能重复，但是需要有序
        //正常情况下，当前的时间年月日时分秒 + 随机数 + 机器id + 约约编号后几位（用户id的相关）
        String orderNo = "";
        //1.确定一个基础时间
        StringBuffer stringBuffer = new StringBuffer(DateUtils.format(new Date(), DateUtils.YYYYMMDDHHMMSSSSS));
        //2.追加一个时间戳
        stringBuffer.append(System.currentTimeMillis());
        orderNo = stringBuffer.toString();
        //3.因为orderNo有可能重复，但是我们不能让他重复
        QueryWrapper<MaintainOrder> qw = new QueryWrapper<>();
        qw.eq("orderNo",orderNo);
        MaintainOrder order = maintainOrderMapper.selectOne(qw);
        //如果不等于null，说明通过刚刚的订单号查询到了数据，说明订单编号重复了
        if (order != null){
            //递归调用自己重新生成，到不重复为止
            return this.createOrderNo();
        }
        return orderNo;
    }


    /**
     * 验证手机格式是否正确
     * @param phone
     * @return
     */
    private boolean checkPhone(String phone){
        //验证手机号不为空
        if(!StringUtils.isBlank(phone)){
            return phone.matches(Constants.PHONE_REGSTR);
        }
        return false;
    }


    /**
     * 验证地址
     * @param address
     * @return
     */
    private boolean checkAddress(String address){
        if (StringUtils.isBlank(address)){
            return false;
        }
        return true;
    }


    /**
     * 验证时间
     *  只需要入参时间大于或者等于当前时间
     *  但是不能超过当前时间4天
     * @param appintDate
     * @return
     */
    private boolean checkDate(Date appintDate){
        //创建一个当前时间
        Date currentDate = DateUtils.getCurrentDate(DateUtils.YYYY_MM_DD);
        //如果这个方法搞不清楚，就把这两个时间计算成毫秒，然后比较
        if (currentDate.compareTo(appintDate) <= 1 ||
            appintDate.compareTo(DateUtils.addDate(currentDate,4)) <= 1){
            return true;
        }
        /*//1970年到现在的总毫秒数
        long current = System.currentTimeMillis();
        long appintDateTime = appintDate.getTime();

        if (appintDateTime >= current){
            return true;
        }*/

        return false;
    }

    /**
     * 验证时间区间
     * @param temporalInterval
     * @return
     */
    private boolean checkTemporalInterval(Integer temporalInterval){
        if (temporalInterval == Constants.Order.TemporalInterval.AM ||
                temporalInterval == Constants.Order.TemporalInterval.NOON ||
                temporalInterval == Constants.Order.TemporalInterval.PM ||
                temporalInterval == Constants.Order.TemporalInterval.NIGHT){
            return true;
        }
        return false;
    }



    /**
     * 验证验证码是否正确
     * @param phone
     * @param sms 用户从页面传递过来的验证码
     * @return
     */
    public boolean checkSmsCode(String phone,String sms){
        //如果不为空，那么就去redis中取
        if (!StringUtils.isBlank(sms)){
            //从redis中取出短信验证码
            String code = getRedisValue(phone);
            return sms.equals(code);
        }

        return false;
    }


    /**
     *  根据手机账号获取redis中的短信验证码
     * @param phone
     * @return
     */
    public String getRedisValue(String phone){
        String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.PREFIX_SMS,
                Constants.Sms.TYPE_REGIST_OR_LOGIN.toString(),phone);
        return redisUtils.getValue(key);
    }
}
